popover: Hide/ungrab on button release
authorCarlos Garnacho <carlosg@gnome.org>
Tue, 28 Jan 2014 13:05:08 +0000 (14:05 +0100)
committerCarlos Garnacho <carlosg@gnome.org>
Tue, 28 Jan 2014 15:18:53 +0000 (16:18 +0100)
If the grab is released during button press, the button release is
just then sent to the widget below the pointer. Depending on the
widget implementation, this could already trigger actions if the
widget does not perform any kind of button state tracking. It is
safer to ungrab on button release so no extra actions are possibly
triggered, and the behavior is uniform across widgets.

But the opposite situation may also happen, that a popover is
shown/grabbed on a button press event, so it'd get the sole button
release event after being shown, so prepare for that case by making
popover ignore single button release events with no preceding button
press.

Fixes issues seen in
https://bugzilla.gnome.org/show_bug.cgi?id=723031#c2

gtk/gtkpopover.c

index d0323b0003dbe17dc94b7d2884dc414baefad922..f635e6bc72f6cf491215a9e6a4eecd16b0ebb7b6 100644 (file)
@@ -84,6 +84,7 @@ struct _GtkPopoverPrivate
   guint final_position     : 2;
   guint current_position   : 2;
   guint modal              : 1;
+  guint button_pressed     : 1;
 };
 
 static GQuark quark_widget_popovers = 0;
@@ -283,6 +284,7 @@ gtk_popover_unmap (GtkWidget *widget)
   GtkPopoverPrivate *priv;
 
   priv = GTK_POPOVER (widget)->priv;
+  priv->button_pressed = FALSE;
 
   if (priv->modal)
     gtk_popover_apply_modality (GTK_POPOVER (widget), FALSE);
@@ -1015,10 +1017,30 @@ static gboolean
 gtk_popover_button_press (GtkWidget      *widget,
                           GdkEventButton *event)
 {
+  GtkPopoverPrivate *priv;
+
+  if (event->type != GDK_BUTTON_PRESS)
+    return GDK_EVENT_PROPAGATE;
+
+  priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
+  priv->button_pressed = TRUE;
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+gtk_popover_button_release (GtkWidget      *widget,
+                           GdkEventButton *event)
+{
+  GtkPopoverPrivate *priv;
   GtkWidget *child;
 
+  priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
   child = gtk_bin_get_child (GTK_BIN (widget));
 
+  if (!priv->button_pressed)
+    return GDK_EVENT_PROPAGATE;
+
   if (child && event->window == gtk_widget_get_window (widget))
     {
       GtkAllocation child_alloc;
@@ -1111,6 +1133,7 @@ gtk_popover_class_init (GtkPopoverClass *klass)
   widget_class->size_allocate = gtk_popover_size_allocate;
   widget_class->draw = gtk_popover_draw;
   widget_class->button_press_event = gtk_popover_button_press;
+  widget_class->button_release_event = gtk_popover_button_release;
   widget_class->key_press_event = gtk_popover_key_press;
   widget_class->grab_focus = gtk_popover_grab_focus;
   widget_class->focus = gtk_popover_focus;